﻿using System.Collections.Generic;
using DatabaseGroup.SSIS.SourceAdapters;
using Microsoft.SqlServer.Dts.Runtime.Wrapper;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
using Microsoft.SqlServer.Dts.Pipeline;
using System;

namespace DatabaseGroup.UnitTests.SSIS.SourceAdapters
{
    [TestClass()]
    public class OutputRuntimePropertiesCacheTest
    {
        private TestContext _testContextInstance;

        private const string _colPropMessage =
            "The returned column property was not the same as the one set on the cached column";

        public TestContext TestContext
        {
            get
            {
                return _testContextInstance;
            }
            set
            {
                _testContextInstance = value;
            }
        }

        [TestMethod()]
        public void Contains_DummyStringColumn_ReturnTrue()
        {
            OutputRuntimePropertiesCache target = CreateInitializedCacheWithDummyColumns();
            Assert.IsTrue(target.Contains("DummyStringColumn"), "A column that was expected to be contained within the cache was not found");
        }

        [TestMethod()]
        public void Contains_DummyIntColumn_ReturnTrue()
        {
            OutputRuntimePropertiesCache target = CreateInitializedCacheWithDummyColumns();
            Assert.IsTrue(target.Contains("DummyIntColumn"), "A column that was expected to be contained within the cache was not found");
        }

        [TestMethod()]
        public void Contains_DummyDecimalColumn_ReturnTrue()
        {
            OutputRuntimePropertiesCache target = CreateInitializedCacheWithDummyColumns();
            Assert.IsTrue(target.Contains("DummyDecimalColumn"), "A column that was expected to be contained within the cache was not found");
        }

        [TestMethod()]
        public void Contains_UnknownColumn_ReturnFalse()
        {
            OutputRuntimePropertiesCache target = CreateInitializedCacheWithDummyColumns();
            Assert.IsFalse(target.Contains("UnknownColumn"), "A non-existant column was found in the cache when it should not be");
        }

        [TestMethod()]
        public void Indexer_LookupDummyStringColumnByName_ReturnExpectedColumnInfo()
        {
            OutputRuntimePropertiesCache target = CreateInitializedCacheWithDummyColumns();
            ColumnInfo ci = target["DummyStringColumn"];

            Assert.AreEqual<int>(1, ci.ID, _colPropMessage);
            Assert.AreEqual<string>("DummyStringColumn", ci.Name, _colPropMessage);
            Assert.AreEqual<DTSRowDisposition>(DTSRowDisposition.RD_FailComponent, ci.ErrorRowDisposition, _colPropMessage);
            Assert.AreEqual<DTSRowDisposition>(DTSRowDisposition.RD_FailComponent, ci.TruncationRowDisposition, _colPropMessage);
            Assert.AreEqual<DataType>(DataType.DT_STR, ci.DataType, _colPropMessage);
            Assert.AreEqual<int>(255, ci.Length, _colPropMessage);
        }

        [TestMethod()]
        public void Indexer_LookupDummyIntColumnByName_ReturnExpectedColumnInfo()
        {
            OutputRuntimePropertiesCache target = CreateInitializedCacheWithDummyColumns();
            ColumnInfo ci = target["DummyIntColumn"];

            Assert.AreEqual<int>(2, ci.ID, _colPropMessage);
            Assert.AreEqual<string>("DummyIntColumn", ci.Name, _colPropMessage);
            Assert.AreEqual<DTSRowDisposition>(DTSRowDisposition.RD_RedirectRow, ci.ErrorRowDisposition, _colPropMessage);
            Assert.AreEqual<DTSRowDisposition>(DTSRowDisposition.RD_RedirectRow, ci.TruncationRowDisposition, _colPropMessage);
            Assert.AreEqual<DataType>(DataType.DT_I4, ci.DataType, _colPropMessage);
            Assert.AreEqual<int>(0, ci.Length, _colPropMessage);
        }

        [TestMethod()]
        public void Indexer_LookupDummyDecimalColumnByName_ReturnExpectedColumnInfo()
        {
            OutputRuntimePropertiesCache target = CreateInitializedCacheWithDummyColumns();
            ColumnInfo ci = target["DummyDecimalColumn"];

            Assert.AreEqual<int>(3, ci.ID, _colPropMessage);
            Assert.AreEqual<string>("DummyDecimalColumn", ci.Name, _colPropMessage);
            Assert.AreEqual<DTSRowDisposition>(DTSRowDisposition.RD_IgnoreFailure, ci.ErrorRowDisposition, _colPropMessage);
            Assert.AreEqual<DTSRowDisposition>(DTSRowDisposition.RD_NotUsed, ci.TruncationRowDisposition, _colPropMessage);
            Assert.AreEqual<DataType>(DataType.DT_DECIMAL, ci.DataType, _colPropMessage);
            Assert.AreEqual<int>(0, ci.Length, _colPropMessage);
        }

        [TestMethod()]
        public void Indexer_LookupDummyStringColumnByIndex_ReturnExpectedColumnInfo()
        {
            OutputRuntimePropertiesCache target = CreateInitializedCacheWithDummyColumns();
            ColumnInfo ci = target[0];

            Assert.AreEqual<string>("DummyStringColumn", ci.Name, "The column found at index 0 is not the one expected to be found");
        }

        [TestMethod()]
        public void Indexer_LookupDummyIntColumnByIndex_ReturnExpectedColumnInfo()
        {
            OutputRuntimePropertiesCache target = CreateInitializedCacheWithDummyColumns();
            ColumnInfo ci = target[1];

            Assert.AreEqual<string>("DummyIntColumn", ci.Name, "The column found at index 1 is not the one expected to be found");
        }

        [TestMethod()]
        public void Indexer_LookupDummyDecimalColumnByIndex_ReturnExpectedColumnInfo()
        {
            OutputRuntimePropertiesCache target = CreateInitializedCacheWithDummyColumns();
            ColumnInfo ci = target[2];

            Assert.AreEqual<string>("DummyDecimalColumn", ci.Name, "The column found at index 2 is not the one expected to be found");
        }

        [TestMethod()]
        [ExpectedException(typeof(KeyNotFoundException), "Expected KeyNotFoundException when calling with a non-existant column name")]
        public void Indexer_LookupUnknownColumnByName_ThrowKeyNotFoundException()
        {
            OutputRuntimePropertiesCache target = CreateInitializedCacheWithDummyColumns();
            ColumnInfo ci = target["Unknown"];
        }

        [TestMethod()]
        [ExpectedException(typeof(ArgumentOutOfRangeException), "Expected ArgumentOutOfRangeException when calling with an out of range column index")]
        public void Indexer_LookupUnknownColumnByIndex_ThrowKeyNotFoundException()
        {
            OutputRuntimePropertiesCache target = CreateInitializedCacheWithDummyColumns();
            ColumnInfo ci = target[9];
        }

        /// <summary>
        /// Instantiates a new OutputRuntimePropertiesCache and then
        /// initializes it with some dummy output columns
        /// </summary>
        /// <returns>The initialized OutputRuntimePropertiesCache</returns>
        private OutputRuntimePropertiesCache CreateInitializedCacheWithDummyColumns()
        {
            IDTSOutput90 output = new OutputTestImpl();
            IDTSBufferManager90 bufferManager = new BufferManagerTestImpl();
            OutputRuntimePropertiesCache target = new OutputRuntimePropertiesCache(output, bufferManager);

            IDTSOutputColumn90 outputColumn = output.OutputColumnCollection.New();
            outputColumn.ID = 1;
            outputColumn.Name = "DummyStringColumn";
            outputColumn.ErrorRowDisposition = DTSRowDisposition.RD_FailComponent;
            outputColumn.TruncationRowDisposition = DTSRowDisposition.RD_FailComponent;
            outputColumn.SetDataTypeProperties(DataType.DT_STR, 255, 0, 0, 1252);

            outputColumn = output.OutputColumnCollection.New();
            outputColumn.ID = 2;
            outputColumn.Name = "DummyIntColumn";
            outputColumn.ErrorRowDisposition = DTSRowDisposition.RD_RedirectRow;
            outputColumn.TruncationRowDisposition = DTSRowDisposition.RD_RedirectRow;
            outputColumn.SetDataTypeProperties(DataType.DT_I4, 0, 0, 0, 0);

            outputColumn = output.OutputColumnCollection.New();
            outputColumn.ID = 3;
            outputColumn.Name = "DummyDecimalColumn";
            outputColumn.ErrorRowDisposition = DTSRowDisposition.RD_IgnoreFailure;
            outputColumn.TruncationRowDisposition = DTSRowDisposition.RD_NotUsed;
            outputColumn.SetDataTypeProperties(DataType.DT_DECIMAL, 0, 4, 2, 0);

            target.InitializeCache();

            return target;
        }
    }
}
